package service

import (
	"context"
	"encoding/json"
	"fmt"
	"fx_swift_ifcgate/api"
	"fx_swift_ifcgate/internal/model"
	"fx_swift_ifcgate/pkg/code"
	"fx_swift_ifcgate/pkg/global"
	"fx_swift_ifcgate/pkg/internalerrors"
	"fx_swift_ifcgate/pkg/logger"
	"fx_swift_ifcgate/pkg/page"
	"fx_swift_ifcgate/pkg/utils"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/jinzhu/copier"
	"github.com/shopspring/decimal"
	"github.com/spf13/cast"
)

// 汇款/收款
type ITransferSrv interface {
	// 国际汇款
	InternationTransfer(ctx context.Context, req *api.InternationTransferReq) error
	// 国内汇款
	DomesticTransfer(ctx context.Context, req *api.DomesticTransferReq) error
	// 国际汇款记录
	InternationTransferList(ctx context.Context, req *api.ITListReq) (*page.Collection[*api.ITListRes], error)
	// 国内汇款记录
	DomesticTransferList(ctx context.Context, req *api.DTListReq) (*page.Collection[*api.DTListRes], error)
	// 国内汇款记录详情
	DomesticTransferDetail(ctx context.Context, merOrderNo string) (*api.DomesticTransferDetailReq, error)
	// 收款记录
	TradeReceiptList(ctx context.Context, req *api.TradeReceiptListReq) (*page.Collection[*api.TradeReceiptInfoRes], error)
	// 提交还原材料
	SubmitTradeOrder(ctx context.Context, rep *api.SubmitTradeOrderReq) error
	// 还原材料关联信息
	TradeOrderMappingInfo(ctx context.Context, flowNo string) (*api.TradeOrderMappingInfoRes, error)
	// 查看还原材料(贸易订单)
	TradeOrderDetail(ctx context.Context, flowNo string) (*api.Tp3013Res, error)
	// 交易手续费预估计算
	CheckoutTradeAmount(ctx context.Context, req *api.CheckoutTradeAmountReq) (*api.CheckoutTradeAmountRes, error)
}

type transferSrv struct {
}

func NewTransferSrv() ITransferSrv {
	return &transferSrv{}
}

// 国际汇款
func (t *transferSrv) InternationTransfer(ctx context.Context, req *api.InternationTransferReq) error {
	var (
		err                 error
		internationPayeeObj *model.IfcgateInternationPayee
		merchantVaInfo      *model.IFCGateMerChantVAInfo
		vainfoCallBack      *model.IFCGateVAInfoCallBack
		tp1004Res           *api.Tp1004Res
		tp1005Res           *api.Tp1005Res
		merchantNo          string
		merOrderNo          string
		merchantToken       string
		account             string
		feeStatus           string
	)
	merchantNo = ctx.Value("MerchantNo").(string)
	feeStatus = ctx.Value("FeeStatus").(string)

	if feeStatus != "1" {
		return internalerrors.New(code.ErrEmptyData, "手续费为配置,无法交易")
	}

	merchantToken, err = GetMerchantToToken(ctx)
	if err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	account, err = GetAccountToMerchantNo(ctx)
	if err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	if err = global.GFDB.Ctx(ctx).Model("ifcgate_internation_payee").
		Where("id=?", req.PayeeId).Scan(&internationPayeeObj); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_merchant_va_info").
		Where("merchant_no", merchantNo).Scan(&merchantVaInfo); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_vainfo_call_back").
		Where("merchant_no", merchantNo).Scan(&vainfoCallBack); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if internationPayeeObj != nil {
		// 组装tp1004接口需要的数据
		tp1004Req := &api.Tp1004Req{}

		tp1004Req.Payee.PayeeFirstName = internationPayeeObj.PayeeFirstName
		tp1004Req.Payee.PayeeLastName = internationPayeeObj.PayeeLastName
		tp1004Req.Payee.PayeeCity = internationPayeeObj.PayeeCity
		tp1004Req.Payee.PayeeProvince = internationPayeeObj.PayeeProvince
		tp1004Req.Payee.PayeeIdNo = internationPayeeObj.PayeeIdNo
		tp1004Req.Payee.PayeeEmail = internationPayeeObj.PayeeEmail
		tp1004Req.Payee.PayeePhone = internationPayeeObj.PayeePhone
		tp1004Req.Payee.PayeeAddress = internationPayeeObj.PayeeAddress
		tp1004Req.Payee.PayeeZipCode = internationPayeeObj.PayeeZipCode
		tp1004Req.Payee.PayeeAcctType = internationPayeeObj.PayeeAcctType
		tp1004Req.Payee.PayeeBankName = internationPayeeObj.PayeeBankName
		tp1004Req.Payee.PayeeBankAccountNo = internationPayeeObj.PayeeBankAccountNo
		tp1004Req.Payee.PayeeBankAddress = internationPayeeObj.PayeeBankAddress
		tp1004Req.Payee.PayeeResidentNo = internationPayeeObj.PayeeRegisterNo
		tp1004Req.Payee.PayeeResidentCountry = internationPayeeObj.PayeeResidentCountry
		tp1004Req.Payee.PayeeBankSwift = internationPayeeObj.PayeeBankSwift
		tp1004Req.Payee.PayeeCompanyName = internationPayeeObj.PayeeCompanyName
		tp1004Req.Payee.BankAcctType = internationPayeeObj.BankAcctType
		tp1004Req.Payee.PayeeBankBranchCode = internationPayeeObj.PayeeBankBranchCode
		tp1004Req.Payee.PayeeCountryCode = internationPayeeObj.CountryCode

		tp1004Req.Payer.PayerCity = merchantVaInfo.RegistrationAddress
		tp1004Req.Payer.PayerType = "01"
		tp1004Req.Payer.PayerPhone = merchantVaInfo.PhoneAreaCode
		tp1004Req.Payer.PayerAddress = merchantVaInfo.RegistrationAddress
		tp1004Req.Payer.PayerCountry = merchantVaInfo.CountryCode
		tp1004Req.Payer.EndSenderName = merchantVaInfo.MerNameEn
		tp1004Req.Payer.PayerBankName = vainfoCallBack.BankName
		tp1004Req.Payer.PayerProvince = internationPayeeObj.PayerProvince
		tp1004Req.Payer.PayerPostalCode = internationPayeeObj.PayerPostalCode
		tp1004Req.Payer.PayerCompanyName = merchantVaInfo.MerNameEn
		if len(merchantVaInfo.CertificateNumber) > 0 {
			tp1004Req.Payer.PayerCompanyRegisterNo = merchantVaInfo.CertificateNumber
		}
		if len(merchantVaInfo.CompanyCertificateNumber) > 0 {
			tp1004Req.Payer.PayerCompanyRegisterNo = merchantVaInfo.CompanyCertificateNumber
		}
		tp1004Req.Payer.PayerIncorporationDate = merchantVaInfo.EstablishDate
		tp1004Req.Payer.PayerRegisteredCountry = merchantVaInfo.CountryCode

		debitAmount, _ := decimal.NewFromString(req.DebitAmount)
		merOrderNo = utils.GenerateCode32()
		tp1004Req.AccountType = "1"
		tp1004Req.DebitAmount = debitAmount.Div(decimal.NewFromFloat(100)).String()
		tp1004Req.ArriveCurrency = req.ArriveCurrency
		tp1004Req.MerOrderNo = merOrderNo
		tp1004Req.DebitCurrency = req.DebitCurrency
		tp1004Req.Purpose = req.Purpose
		tp1004Req.PurposeRemark = req.PurposeRemark
		tp1004Req.PayType = internationPayeeObj.PayType
		tp1004Req.CountryCode = internationPayeeObj.CountryCode
		logger.SugarLogger.Infof("单号：%s", merOrderNo)
		tp1004Res, err = PostTp1004(tp1004Req, merchantToken)
		if err != nil && tp1004Res == nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		// 组装tp1005接口需要的数据,最终提交
		tp1005Res, err = PostTp1005(&api.Tp1005Req{
			QuoteId:     cast.ToString(tp1004Res.Body.QuoteId),
			CallbackUrl: global.ViperObj.GetString("callback.tp1005"),
		}, merchantToken)
		if err != nil && tp1005Res == nil {
			logger.SugarLogger.Errorf("单号为:%s", merOrderNo)
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if _, err = global.GFDB.Insert(ctx, "ifcgate_internation_transfer_record", &model.IfcgateInternationTransferRecord{
			MerchantNo:     merchantNo,
			Account:        account,
			PayeeId:        cast.ToInt64(req.PayeeId),
			QuoteId:        tp1005Res.Body.QuoteId,
			CountryCode:    tp1005Res.Body.CountryCode,
			ArriveAmount:   tp1005Res.Body.ArriveAmount,
			ArriveCurrency: tp1005Res.Body.ArriveCurrency,
			DebitCurrency:  tp1005Res.Body.DebitCurrency,
			DebitAmount:    tp1005Res.Body.DebitAmount,
			PayType:        tp1005Res.Body.PayType,
			AccountType:    tp1005Res.Body.AccountType,
			Rate:           tp1005Res.Body.Rate,
			Status:         tp1005Res.Body.Status,
			Code:           tp1005Res.Body.Code,
			Message:        tp1005Res.Body.Message,
			BizFlow:        tp1005Res.Body.BizFlow,
			FxBizFlow:      tp1005Res.Body.FixBizFlow,
			MerOrderNo:     tp1005Res.Body.MerOrderNo,
			Purpose:        req.Purpose,
			TradeComments:  req.TradeComments,
			PurposeRemark:  req.PurposeRemark,
		}); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}

// 国内汇款
func (t *transferSrv) DomesticTransfer(ctx context.Context, req *api.DomesticTransferReq) error {
	g.Dump("国内汇款入参打印:", req)
	var (
		err              error
		merchantNo       string
		merOrderNo       string
		tp1001Res        *api.Tp1001Res
		tp1019Res        *api.Tp1019Res
		domesticPayeeObj *model.IfcgateDomesticPayee
		payOrderList     = make([]api.PayOrderList, 0)
		payReduceList    = make([]api.PayReduceList, 0)
		merchantToken    string
		account          string
		feeStatus        string
	)

	merchantNo = ctx.Value("MerchantNo").(string)

	feeStatus = ctx.Value("FeeStatus").(string)
	if feeStatus != "1" {
		return internalerrors.New(code.ErrEmptyData, "手续费为配置,无法交易")
	}

	merchantToken, err = GetMerchantToToken(ctx)
	if err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	account, err = GetAccountToMerchantNo(ctx)
	if err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	if err = global.GFDB.Ctx(ctx).Model("ifcgate_domestic_payee").
		Where("id=?", req.PayeeId).Scan(&domesticPayeeObj); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if domesticPayeeObj != nil {
		merOrderNo = utils.GenerateCode32()
		tp1001 := &api.Tp1001Req{}
		tp1001.CallbackUrl = global.ViperObj.GetString("callback.tp1001")
		tp1001.MerOrderNo = merOrderNo
		tp1001.PaymentType = req.PaymentType
		tp1001.SettlementType = req.SettlementType
		tp1001.FileUrlPath = OperatorImageToSftp(req.FileUrlPath)

		payOrderList = append(payOrderList, api.PayOrderList{
			DebitAmount:           cast.ToInt64(req.PayOrderRequest.DebitAmount),
			CNAPSCode:             req.PayOrderRequest.CNAPSCode,
			DeclarationCurrency:   req.PayOrderRequest.DeclarationCurrency,
			DebitCurrency:         req.PayOrderRequest.DebitCurrency,
			Identity:              req.PayOrderRequest.Identity,
			Mobile:                req.PayOrderRequest.Mobile,
			MerSingleNo:           utils.GenerateCode32(),
			PayeeAccountNo:        req.PayOrderRequest.PayeeAccountNo,
			PayMethod:             req.PayOrderRequest.PayMethod,
			PayeeName:             req.PayOrderRequest.PayeeName,
			RegistrationRegion:    domesticPayeeObj.RegistrationRegion,
			SenderIncorporationNo: domesticPayeeObj.SenderIncorporationNo,
			TradeCodeType:         req.PayOrderRequest.TradeCodeType,
			SenderName:            domesticPayeeObj.SenderName,
			SenderBankName:        domesticPayeeObj.SenderBankName,
		})
		tp1001.PayOrderList = payOrderList

		for _, valueObj := range req.PayReduce {
			payReduceList = append(payReduceList, api.PayReduceList{
				OrderNo:       valueObj.OrderNo,
				OrderCurrency: valueObj.OrderCurrency,
				OrderAmount:   cast.ToInt64(valueObj.OrderAmount),
				OrderDate:     valueObj.OrderDate,
				GoodNumber:    valueObj.GoodNumber,
				GoodsName:     valueObj.GoodsName,
				PlatformName:  valueObj.PlatformName,
				Purpose:       valueObj.Purpose,
				StoreLink:     valueObj.StoreLink,
				WlName:        valueObj.WlName,
				WlSeqno:       valueObj.WlSeqno,
				PayeeAcctNo:   valueObj.PayeeAcctNo,
				SellerId:      valueObj.SellerId,
				SellerName:    valueObj.SellerName,
				GoodsCategory: valueObj.GoodsCategory,
			})
		}
		tp1001.PayReduceList = payReduceList
		if req.PayOrderRequest.DebitCurrency == "CNY" {
			tp1001Res, err = PostTp1001(tp1001, merchantToken)
			if err != nil || tp1001Res == nil {
				logger.SugarLogger.Errorf("单号为:%s", merOrderNo)
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
			for _, valueObj := range req.PayReduce {
				global.GFDB.Ctx(ctx).Model("ifcgate_domestic_transfer_order").Insert(&model.IfcgateDomesticTransferOrder{
					MerOrderNo:    merOrderNo,
					GoodsName:     valueObj.GoodsName,
					GoodNumber:    valueObj.GoodNumber,
					OrderCurrency: valueObj.OrderCurrency,
					OrderAmount:   valueObj.OrderAmount,
					OrderDate:     valueObj.OrderDate,
					PlatformName:  valueObj.PlatformName,
					Purpose:       valueObj.Purpose,
					StoreLink:     valueObj.StoreLink,
					WlName:        valueObj.WlName,
					WlSeqno:       valueObj.WlSeqno,
					PayeeAcctNo:   valueObj.PayeeAcctNo,
					OrderNo:       valueObj.OrderNo,
					SellerName:    valueObj.SellerName,
					SellerId:      valueObj.SellerId,
					GoodsCategory: valueObj.GoodsCategory,
				})
			}
			if _, err = global.GFDB.Insert(ctx, "ifcgate_domestic_transfer_record", &model.IfcgateDomesticTransferRecord{
				MerchantNo:     merchantNo,
				Account:        account,
				MerOrderNo:     merOrderNo,
				SettlementType: req.SettlementType,
				PayeeId:        cast.ToInt64(req.PayeeId),
				BizFlowNo:      tp1001Res.Body.BizFlowNo,
				QuoteId:        cast.ToInt64(tp1001Res.Body.QuoteId),
				DebitCurrency:  tp1001Res.Body.DebitCurrency,
				DebitAmount:    cast.ToFloat64(decimal.NewFromFloat(tp1001Res.Body.DebitAmount).Div(decimal.NewFromFloat(100)).String()),
				Amount:         cast.ToFloat64(decimal.NewFromFloat(tp1001Res.Body.Amount).Div(decimal.NewFromFloat(100)).String()),
				Rate:           cast.ToString(tp1001Res.Body.Rate),
				FeeCurrency:    tp1001Res.Body.FeeCurrency,
				FeeAmount:      cast.ToFloat64(decimal.NewFromFloat(tp1001Res.Body.FeeAmount).Div(decimal.NewFromFloat(100)).String()),
				Status:         tp1001Res.Body.Status,
				TradeComments:  req.PayOrderRequest.TradeComments,
				TradeCodeType:  req.PayOrderRequest.TradeCodeType,
				FileUrlPath:    req.FileUrlPath,
			}); err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
		} else if req.PayOrderRequest.DebitCurrency != "CNY" {
			tp1001Res, err = PostTp1001(tp1001, merchantToken)
			if err != nil || tp1001Res == nil {
				logger.SugarLogger.Errorf("单号为:%s", merOrderNo)
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
			logger.SugarLogger.Infof("quoteId :%d", tp1001Res.Body.QuoteId)
			// 调用tp1019接口最终提交
			tp1019Res, err = PostTp1019(&api.Tp1019Req{
				QuoteId: cast.ToString(tp1001Res.Body.QuoteId),
			}, merchantToken)
			if err != nil || tp1019Res == nil {
				logger.SugarLogger.Errorf("单号为:%s", merOrderNo)
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
			for _, valueObj := range req.PayReduce {
				global.GFDB.Ctx(ctx).Model("ifcgate_domestic_transfer_order").Insert(&model.IfcgateDomesticTransferOrder{
					MerOrderNo:    merOrderNo,
					GoodsName:     valueObj.GoodsName,
					GoodNumber:    valueObj.GoodNumber,
					OrderCurrency: valueObj.OrderCurrency,
					OrderAmount:   valueObj.OrderAmount,
					OrderDate:     valueObj.OrderDate,
					PlatformName:  valueObj.PlatformName,
					Purpose:       valueObj.Purpose,
					StoreLink:     valueObj.StoreLink,
					WlName:        valueObj.WlName,
					WlSeqno:       valueObj.WlSeqno,
					PayeeAcctNo:   valueObj.PayeeAcctNo,
					OrderNo:       valueObj.OrderNo,
					SellerName:    valueObj.SellerName,
					SellerId:      valueObj.SellerId,
					GoodsCategory: valueObj.GoodsCategory,
				})
			}
			if _, err = global.GFDB.Insert(ctx, "ifcgate_domestic_transfer_record", &model.IfcgateDomesticTransferRecord{
				MerchantNo:     merchantNo,
				Account:        account,
				MerOrderNo:     merOrderNo,
				SettlementType: req.SettlementType,
				PayeeId:        cast.ToInt64(req.PayeeId),
				BizFlowNo:      tp1019Res.Body.BizFlowNo,
				QuoteId:        tp1019Res.Body.QuoteId,
				DebitCurrency:  tp1019Res.Body.DebitCurrency,
				DebitAmount:    cast.ToFloat64(decimal.NewFromFloat(tp1019Res.Body.DebitAmount).Div(decimal.NewFromFloat(100)).String()),
				Amount:         cast.ToFloat64(decimal.NewFromFloat(tp1019Res.Body.Amount).Div(decimal.NewFromFloat(100)).String()),
				Rate:           cast.ToString(tp1019Res.Body.Rate),
				FeeCurrency:    tp1019Res.Body.FeeCurrency,
				FeeAmount:      cast.ToFloat64(decimal.NewFromFloat(tp1019Res.Body.FeeAmount).Div(decimal.NewFromFloat(100)).String()),
				Status:         tp1019Res.Body.Status,
				TradeCodeType:  req.PayOrderRequest.TradeCodeType,
				FileUrlPath:    req.FileUrlPath,
			}); err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
		}
	}
	return err
}

// 国际汇款记录
func (t *transferSrv) InternationTransferList(ctx context.Context, req *api.ITListReq) (*page.Collection[*api.ITListRes], error) {
	var (
		err        error
		total      int
		merchantNo string
		resultList []*api.ITListRes
	)

	collectionDto := &page.Collection[*api.ITListRes]{}
	collectionDto.Page = uint64(req.PageNo)
	collectionDto.PageSize = uint64(req.PageSize)

	merchantNo = ctx.Value("MerchantNo").(string)
	if len(merchantNo) > 0 {
		mod := global.GFDB.Ctx(ctx).Model("ifcgate_internation_transfer_record itr")
		mod.LeftJoin("ifcgate_internation_payee iip", "itr.payee_id=iip.id")
		mod.Fields("iip.payee_first_name,iip.payee_last_name,iip.payee_bank_account_no," +
			"itr.biz_flow as biz_flow_no,itr.arrive_amount,itr.debit_amount,itr.rate,itr.fee_amt,itr.status,itr.fee_currency,iip.payee_company_name," +
			"itr.created_at,itr.updated_at,itr.purpose_remark,itr.trade_comments,itr.purpose,itr.debit_currency,itr.arrive_currency,itr.message as resp_desc,itr.pay_type")
		if len(req.BizFlow) > 0 {
			mod.WhereLike("itr.biz_flow", "%"+req.BizFlow+"%")
		}
		if len(req.Status) > 0 {
			mod.Where("itr.status=?", req.Status)
		}
		if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
			mod.Where("itr.created_at >=? and itr.created_at < ?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
		}
		mod.Where("itr.merchant_no=?", merchantNo)
		mod.Order("itr.created_at desc")
		mod.Limit(int(page.PageToOffset(uint64(req.PageNo), uint64(req.PageSize))), cast.ToInt(req.PageSize))
		err = mod.ScanAndCount(&resultList, &total, false)
		collectionDto.TotalPage = page.GetTotalPage(uint64(req.PageNo), uint64(req.PageSize), cast.ToInt64(total))
		if err != nil {
			return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
		}
		collectionDto.Total = cast.ToInt64(total)
		collectionDto.List = resultList
	}
	return collectionDto, err
}

// 国内汇款记录
func (t *transferSrv) DomesticTransferList(ctx context.Context, req *api.DTListReq) (*page.Collection[*api.DTListRes], error) {
	var (
		err        error
		total      int
		merchantNo string
		resultList []*api.DTListRes
	)

	collectionDto := &page.Collection[*api.DTListRes]{}
	collectionDto.Page = uint64(req.PageNo)
	collectionDto.PageSize = uint64(req.PageSize)

	merchantNo = ctx.Value("MerchantNo").(string)
	if len(merchantNo) > 0 {

		NewVAInfoSrv().GetTradeCodeType(context.Background())

		mod := global.GFDB.Ctx(ctx).Model("ifcgate_domestic_transfer_record idr")
		mod.LeftJoin("ifcgate_domestic_payee idp", "idr.payee_id=idp.id")
		mod.Fields("idp.payee_name,idp.bank_acct_no," +
			"idr.biz_flow_no,idr.amount,idr.debit_amount,idr.debit_currency,idr.status,idr.rate,idr.fee_amount," +
			"idr.status,idr.fee_currency,idr.fee_amount as feeAmt,idr.created_at,idr.settlement_type,idr.updated_at,idr.resp_desc,idr.mer_order_no,idr.trade_code_type")
		if len(req.BizFlowNo) > 0 {
			mod.WhereLike("idr.biz_flow_no", "%"+req.BizFlowNo+"%")
		}
		if len(req.Status) > 0 {
			mod.Where("idr.status=?", req.Status)
		}
		if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
			mod.Where("idr.created_at >=? and idr.created_at <= ?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
		}
		mod.Where("idr.merchant_no=?", merchantNo)
		mod.Order("idr.created_at desc")
		mod.Limit(int(page.PageToOffset(uint64(req.PageNo), uint64(req.PageSize))), cast.ToInt(req.PageSize))
		err = mod.ScanAndCount(&resultList, &total, false)
		collectionDto.TotalPage = page.GetTotalPage(uint64(req.PageNo), uint64(req.PageSize), cast.ToInt64(total))
		if err != nil {
			return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
		}
		for _, value := range resultList {
			if _, ok := global.TradeCodeMap[value.TradeCodeType]; ok {
				value.TradeCodeType = global.TradeCodeMap[value.TradeCodeType]
			}
		}
		collectionDto.Total = cast.ToInt64(total)
		collectionDto.List = resultList
	}
	return collectionDto, err
}

// 收款记录
func (t *transferSrv) TradeReceiptList(ctx context.Context, req *api.TradeReceiptListReq) (*page.Collection[*api.TradeReceiptInfoRes], error) {
	var (
		err        error
		total      int
		merchantNo string
		resultList []*api.TradeReceiptInfoRes
	)

	collectionDto := &page.Collection[*api.TradeReceiptInfoRes]{}
	collectionDto.Page = uint64(req.PageNo)
	collectionDto.PageSize = uint64(req.PageSize)

	merchantNo = ctx.Value("MerchantNo").(string)
	if len(merchantNo) > 0 {
		mod := global.GFDB.Ctx(ctx).Model("ifcgate_trade_receipt itr").
			LeftJoin("ifcgate_vainfo_call_back ivcb", "itr.va_account=ivcb.account_no").
			LeftJoin("ifcgate_trade_order_call_back itocab", "itocab.flow_no=itr.flow_no").
			Fields("itr.flow_no,itr.receive_amount,itr.receive_currency,itr.actual_receive_amount,itr.sender_name,itr.sender_account," +
				"itr.created_at,itr.fee_amount,itr.fee_currency,itr.trade_status,itr.trade_message,ivcb.account_name,ivcb.account_no,itocab.status as trade_submit_status")
		if len(req.FlowNo) > 0 {
			mod.WhereLike("itr.flow_no", "%"+req.FlowNo+"%")
		}
		if len(req.ReceiveCurrency) > 0 {
			mod.Where("itr.receive_currency=?", req.ReceiveCurrency)
		}
		if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
			mod.Where("itr.created_at >=? and itr.created_at < ?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
		}
		mod.Where("itr.merchant_no=?", merchantNo)
		mod.Order("itr.created_at desc")
		mod.Limit(int(page.PageToOffset(uint64(req.PageNo), uint64(req.PageSize))), cast.ToInt(req.PageSize))
		err = mod.ScanAndCount(&resultList, &total, false)
		collectionDto.TotalPage = page.GetTotalPage(uint64(req.PageNo), uint64(req.PageSize), cast.ToInt64(total))
		if err != nil {
			return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
		}
		collectionDto.Total = cast.ToInt64(total)
		collectionDto.List = resultList
	}
	return collectionDto, err
}

// 提交还原材料
func (t *transferSrv) SubmitTradeOrder(ctx context.Context, req *api.SubmitTradeOrderReq) error {
	var (
		err           error
		tp1012Res     *api.Tp1012Res
		merOrderNo    string
		merchantNo    string
		count         int
		pathList      = make([]string, 0)
		annexUrlList  = make([]string, 0)
		proveUrl      = make([]string, 0)
		objStr        []byte
		ser           api.ServiceTradeObj
		merchantToken string
		account       string
		feeStatus     string
	)
	merchantNo = ctx.Value("MerchantNo").(string)

	feeStatus = ctx.Value("FeeStatus").(string)
	if feeStatus != "1" {
		return internalerrors.New(code.ErrEmptyData, "手续费为配置,无法交易")
	}

	merchantToken, err = GetMerchantToToken(ctx)
	if err != nil {
		logger.SugarLogger.Error(err.Error())
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	account, err = GetAccountToMerchantNo(ctx)
	if err != nil {
		logger.SugarLogger.Error(err.Error())
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	if len(req.GoodsList) > 10 {
		return internalerrors.New(code.ErrUnknown, "物品数量不超过10个")
	}
	pathList = OperatorImageToSftpArray(req.TranscationCert)
	if len(req.AnnexUrl) > 0 {
		annexUrlList = OperatorImageToSftpArray(req.AnnexUrl)
	}
	if len(req.ServiceTrade.ProveUrl) > 0 {
		ser = api.ServiceTradeObj{}
		proveUrl = OperatorImageToSftpArray(req.ServiceTrade.ProveUrl)
		ser.ProveUrl = proveUrl
		ser.ServiceCondition = req.ServiceTrade.ServiceCondition
		ser.ConditionDate = req.ServiceTrade.ConditionDate
	} else {
		ser = api.ServiceTradeObj{}
		ser.ServiceCondition = req.ServiceTrade.ServiceCondition
		ser.ConditionDate = req.ServiceTrade.ConditionDate
	}
	merOrderNo = utils.GenerateCode32()
	obj := &api.Tp1012Req{
		Amount:          cast.ToInt(req.Amount),
		BuyerArea:       req.BuyerArea,
		BuyerName:       req.BuyName,
		Currency:        req.Currency,
		CallbackUrl:     global.ViperObj.GetString("callback.tp1012"),
		GoodsList:       req.GoodsList,
		LogCompany:      req.LogCompany,
		LogNo:           req.LogNo,
		LogStatus:       req.LogStatus,
		MerOrderNo:      merOrderNo,
		ServiceTrade:    ser,
		TradeType:       req.TradeType,
		TranscationCert: pathList,
		TranscationDate: req.TranscationDate,
		AnnexUrl:        annexUrlList,
	}
	tp1012Res, err = PostTp1012(obj, merchantToken)
	if err != nil || tp1012Res == nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(tp1012Res.Body.ContractNo) > 0 {
		obj.TranscationCert = req.TranscationCert
		obj.AnnexUrl = req.AnnexUrl
		objStr, _ = json.Marshal(&obj)
		if _, err = global.GFDB.Ctx(ctx).Model("ifcgate_trade_receipt_order").Insert(&model.IfcgateTradeReceiptOrder{
			MerOrderNo: merOrderNo,
			JsonStr:    string(objStr),
		}); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		return global.GFDB.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
			if count, err = global.GFDB.Ctx(ctx).Model("ifcgate_trade_order_call_back").
				Where("flow_no=?", req.FlowNo).Count(); err != nil {
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
			if count > 0 {
				if _, err = tx.Model("ifcgate_trade_order_call_back").
					Where("flow_no=?", req.FlowNo).Delete(); err != nil {
					return internalerrors.New(code.ErrUnknown, err.Error())
				}
				g.Redis().Del(ctx, tp1012Res.Body.ContractNo)
			}
			if _, err = tx.Insert("ifcgate_trade_order_call_back", &model.IfcgateTradeOrderCallBack{
				FlowNo:     req.FlowNo,
				MerchantNo: merchantNo,
				Account:    account,
				MerOrderNo: merOrderNo,
				ContractNo: tp1012Res.Body.ContractNo,
				Currency:   req.Currency,
				Amount:     cast.ToFloat64(req.Amount),
				TradeType:  req.TradeType,
				Status:     "INIT",
				Message:    "",
			}); err != nil {
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
			return nil
		})
	}
	return err
}

// 还原材料关联信息
func (t *transferSrv) TradeOrderMappingInfo(ctx context.Context, flowNo string) (*api.TradeOrderMappingInfoRes, error) {
	var (
		err               error
		tradeOrderMappObj *api.TradeOrderMappingInfoRes
	)
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_trade_order_mapping_flow").Where("flow_no=?", flowNo).
		Scan(&tradeOrderMappObj); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return tradeOrderMappObj, err
}

// 查看还原材料(贸易订单)
func (t *transferSrv) TradeOrderDetail(ctx context.Context, flowNo string) (*api.Tp3013Res, error) {
	var (
		err                   error
		merchantNo            string
		tradeOrderCallBackObj *model.IfcgateTradeOrderCallBack
		tradeReceiptOrder     *model.IfcgateTradeReceiptOrder
		obj                   api.Tp1012Req
		cObj                  api.ContractListInfo
	)
	merchantNo = ctx.Value("MerchantNo").(string)
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_trade_order_call_back").
		Where("merchant_no=? and flow_no=?", merchantNo, flowNo).Scan(&tradeOrderCallBackObj); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	tp3031Res := &api.Tp3013Res{}
	if tradeOrderCallBackObj != nil {
		if err = global.GFDB.Ctx(ctx).Model("ifcgate_trade_receipt_order").
			Where("mer_order_no=?", tradeOrderCallBackObj.MerOrderNo).Scan(&tradeReceiptOrder); err != nil {
			logger.SugarLogger.Error(err)
			return nil, internalerrors.New(code.ErrUnknown, err.Error())
		}
		json.Unmarshal([]byte(tradeReceiptOrder.JsonStr), &obj)
		copier.Copy(&cObj, &obj)
		tp3031Res.Body.ContractList = append(tp3031Res.Body.ContractList, cObj)
	}
	return tp3031Res, err
}

// 国内汇款记录详情
func (t *transferSrv) DomesticTransferDetail(ctx context.Context, merOrderNo string) (*api.DomesticTransferDetailReq, error) {
	var (
		err               error
		transferRecordObj *model.IfcgateDomesticTransferRecord
		transferOrderList []*model.IfcgateDomesticTransferOrder
		result            = &api.DomesticTransferDetailReq{}
		list              = make([]api.TradeOrderInfo, 0)
	)
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_domestic_transfer_record").
		Where("mer_order_no=?", merOrderNo).Scan(&transferRecordObj); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(transferRecordObj.FileUrlPath) > 0 {
		result.FileUrlPath = transferRecordObj.FileUrlPath
		return result, err
	}
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_domestic_transfer_order").
		Where("mer_order_no=?", merOrderNo).Scan(&transferOrderList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(transferOrderList) > 0 {
		for _, value := range transferOrderList {
			list = append(list, api.TradeOrderInfo{
				GoodNumber:    value.GoodNumber,
				GoodsName:     value.GoodsName,
				OrderAmount:   value.OrderAmount,
				OrderCurrency: value.OrderCurrency,
				OrderNo:       value.OrderNo,
				OrderDate:     value.OrderDate,
				PlatformName:  value.PlatformName,
				Purpose:       value.Purpose,
				StoreLink:     value.StoreLink,
				WlName:        value.WlName,
				WlSeqno:       value.WlSeqno,
				PayeeAcctNo:   value.PayeeAcctNo,
				SellerId:      value.SellerId,
				SellerName:    value.SellerName,
				GoodsCategory: value.GoodsCategory,
			})
		}
		result.TradeOrderInfo = list
	}
	return result, err
}

// 交易手续费预估计算
func (t *transferSrv) CheckoutTradeAmount(ctx context.Context, req *api.CheckoutTradeAmountReq) (*api.CheckoutTradeAmountRes, error) {
	var (
		finalTradeType    string
		finalFee          float64
		finalAmount       float64
		companyIfcgateFee *model.IfcgateFee
		finalRate         float64
		ipOnj             *model.IfcgateInternationPayee
		sellAmount        float64
		merchantNo        string
		err               error
		result            = &api.CheckoutTradeAmountRes{}
	)
	g.Dump("入参为：", req)
	sellAmount = cast.ToFloat64(req.Amount) / 100

	merchantNo = ctx.Value("MerchantNo").(string)
	// 企业
	if err = global.GFDB.Model("ifcgate_fee").
		Where("merchant_no=? and fee_type='00' and status='1'", merchantNo).
		Scan(&companyIfcgateFee); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	if req.PayMethod == "0" { // 人民币结汇
		if req.TradeType == "TRADE" || req.TradeType == "TRADE_OFFLINE" || req.TradeType == "E_COMMERCE" {
			finalTradeType = "00"
		} else {
			finalTradeType = "01"
		}
		if req.SellCurrency != "CNY" {
			sellAmount, _ = ExchangeRateConversion(req.SellCurrency, "CNY", sellAmount)
		}
		// 00-普通结汇 10-极速结汇
		if req.SettlementType == "00" {
			// 00-货物贸易
			if finalTradeType == "00" {
				finalFee = companyIfcgateFee.GtPaymentFee*sellAmount + companyIfcgateFee.GtPaymentFixedFee
			} else if finalTradeType == "01" { // 01-服务贸易
				finalFee = companyIfcgateFee.StPaymentFee*sellAmount + companyIfcgateFee.StPaymentFixedFee
			}
		} else if req.SettlementType == "10" {
			if finalTradeType == "00" {
				finalFee = (companyIfcgateFee.GtPaymentFee+companyIfcgateFee.GtSpeedPaymentFee)*sellAmount + (companyIfcgateFee.GtPaymentFixedFee + companyIfcgateFee.GtSpeedPaymentFixedFee)
			}
		}
	} else if req.PayMethod == "1" { // 国际汇款
		if req.SellCurrency != "USD" {
			sellAmount, _ = ExchangeRateConversion(req.SellCurrency, "USD", sellAmount)
		}
		if err = global.GFDB.Ctx(ctx).Model("ifcgate_internation_payee").
			Where("id=?", req.PayeeId).Scan(&ipOnj); err != nil {
			return nil, internalerrors.New(code.ErrUnknown, err.Error())
		}
		if ipOnj.PayType == "local" && ipOnj.CountryCode == "HK" {
			finalFee = companyIfcgateFee.HkLocalPaymentFee*sellAmount + companyIfcgateFee.HkLocalPaymentFixedFee
		} else if ipOnj.PayType == "swift" {
			finalFee = companyIfcgateFee.InternationalPaymentFee*sellAmount + companyIfcgateFee.InternationalPaymentFixedFee
		}
	}
	if req.BuyCurrency != req.SellCurrency {
		finalAmount, finalRate = ExchangeRateConversion(req.SellCurrency, req.BuyCurrency, cast.ToFloat64(req.Amount)/100)
	} else {
		finalRate = 1
		finalAmount = cast.ToFloat64(req.Amount) / 100
	}

	result.Fee = fmt.Sprintf("%.4f", finalFee)
	result.Rate = fmt.Sprintf("%.4f", finalRate)
	result.Amount = fmt.Sprintf("%.4f", finalAmount)
	return result, err
}

// 根据卖出金额和币种换算 买入金额和汇率
// 1CNY = 0.7232USD
func ExchangeRateConversion(sellCurrency, buyCurrency string, sellAmount float64) (finalBuyAmount float64, FinalRate float64) {
	var (
		err        error
		rateObj    *model.IfcgateRate
		tUsdAmount float64
		tAmount    float64
		rate       float64
	)
	// 计算买入币种价格
	if sellCurrency != "USD" {
		if err = global.GFDB.Model("ifcgate_rate").
			Scan(&rateObj, "currency=?", sellCurrency); err != nil {
			logger.SugarLogger.Error(err)
			return 0, 0
		}
		// 先把卖出币种换成美元
		tUsdAmount = sellAmount / rateObj.Rate

		if buyCurrency != "USD" {
			// 计算买入换汇价格
			if err = global.GFDB.Model("ifcgate_rate").
				Scan(&rateObj, "currency=?", buyCurrency); err != nil {
				logger.SugarLogger.Error(err)
				return 0, 0
			}
			tAmount = tUsdAmount * rateObj.Rate
		} else {
			tAmount = tUsdAmount
		}
		rate = tAmount / sellAmount
	} else {
		if err = global.GFDB.Model("ifcgate_rate").
			Scan(&rateObj, "currency=?", buyCurrency); err != nil {
			logger.SugarLogger.Error(err)
			return 0, 0
		}
		// 先把卖出币种换成美元
		tAmount = sellAmount * rateObj.Rate
		rate = rateObj.Rate
	}
	return tAmount, rate
}
